<!--
 * @Author: fanyoubang
 * @Date: 2021-02-23 16:29:47
 * @LastEditTime: 2021-04-19 14:44:03
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \newxine:\xj-house\src\xjwDesign\xjw-tabs\index.vue
-->
<template>
  <view class="xjw-tabs">
    <view :id="id">
      <scroll-view
        scroll-x
        class="xjw-tabs-scroll-view"
        :scroll-left="scrollLeft"
        scroll-with-animation
      >
        <view
          class="xjw-tabs-scroll-box"
          :class="[
            { 'xjw-tabs-tabs-scorll-flex': !isScroll },
            { 'xjw-tabs-scroll-box--border-btm': showBorder },
          ]"
          :style="{ margin: `0 ${scrollMargin}rpx` }"
        >
          <view
            class="xjw-tabs-tab-item xjw-tabs-line-1"
            :id="'xjw-tabs-tab-item-' + index"
            v-for="(item, index) in list"
            :key="index"
            @tap="clickTab(index)"
            :style="[tabItemStyle(index)]"
          >
            {{ item[name] || item["name"] }}
            <view
              class="xjw-tabs_dot"
              v-if="current != index && item.showDot"
            ></view>
          </view>
          <view
            v-if="showBar"
            class="xjw-tabs-tab-bar"
            :style="[tabBarStyle]"
          ></view>
        </view>
      </scroll-view>
    </view>
  </view>
</template>
<script lang="ts">
import Vue, { PropType } from "vue";
import { Component, Prop, Watch } from "vue-property-decorator";
import { guid } from "../lib/utils/utils";
import { addUnit } from "../lib/function/index";
interface tabBarStyle {
  width: string;
  height: string;
  transform: string;
  "transition-duration": string;
  "border-radius": string;
  "background-color"?: string;
}
interface tabItemStyle {
  width: string;
  height?: string;
  "font-size": string;
  "transition-duration": string;
  "margin-right": string;
  fontWeight?: string;
  color?: string;
  "padding-bottom": string;
  "line-height": string;
}
interface tabQueryInfoItem {
  width: number;
  height: number;
  top: number;
  left: number;
  bottom: number;
  right: number;
}
@Component
export default class Index extends Vue {
  // 导航菜单是否需要滚动，如只有2或者3个的时候，就不需要滚动了，此时使用flex平分tab的宽度
  @Prop({ type: Boolean, default: false }) isScroll;
  // 需循环的标签列表
  @Prop({ type: Array as PropType<Array<any>>, default: [] }) list;
  // 当前活动tab的索引
  @Prop({ type: [Number, String], default: 0 }) current;
  // 导航栏的高度和行高
  @Prop({ type: [Number, String], default: 80 }) height;
  // 字体大小
  @Prop({ type: [Number, String], default: 32 }) fontSize;
  // 过渡动画时长, 单位ms
  @Prop({ type: [Number, String], default: 0.5 }) duration;
  // 移动bar的高度
  @Prop({ type: [Number, String], default: 6 }) barHeight;
  // 单个tab的右边距
  @Prop({ type: [Number, String], default: 30 }) gutter;
  // 读取传入的数组对象的属性
  @Prop({ type: String, default: "name" }) name;
  // 默认字体是否加粗
  @Prop({ type: Boolean, default: true }) fontBold;
  // 活动tab字体是否加粗
  @Prop({ type: Boolean, default: true }) bold;
  // 是否显示底部的滑块
  @Prop({ type: Boolean, default: true }) showBar;
  // 标签的宽度
  @Prop({ type: [Number, String], default: "auto" }) itemWidth;
  // 未选中项的颜色
  @Prop({ type: String, default: "#303133" }) inactiveColor;
  // 选中项的颜色
  @Prop({ type: String, default: "#3171F3" }) activeColor;
  // bar的圆角
  @Prop({ type: String, default: "6rpx" }) barRadius;
  // 文字和bar的间距
  @Prop({ type: [Number, String], default: 16 }) barPad;
  // 是否显示底部border-bottom
  @Prop({ type: Boolean, default: true }) showBorder;
  // scroll-box的边距
  @Prop({ type: Number, default: 0 }) scrollMargin;
  //barColor color
  @Prop({ type: String, default: "" }) barColor;
  @Prop({ type: String, default: "" }) activeSize;
  // 是否显示提示圆点
  @Prop({ type: Boolean, default: false }) showDot;
  id: string = guid();
  scrollLeft: number = 0;
  tabQueryInfo: Array<tabQueryInfoItem> = [];
  componentWidth: number = 0;
  scrollBarLeft: number = 0;
  parentLeft: number = 0;
  currentIndex: number | string = 0;
  barFirstTimeMove: Boolean = true;
  barWidth: number | string = 0;
  get tabBarStyle() {
    const style: tabBarStyle = {
      width: this.barWidth + "rpx",
      height: this.barHeight + "rpx",
      transform: `translate(${this.scrollBarLeft}px, 0)`,
      "transition-duration": `${this.barFirstTimeMove ? 0 : this.duration}s`,
      "border-radius": `${this.barRadius}`,
    };
    if (this.barColor) {
      style["background"] = this.barColor;
    }
    return style;
  }
  @Watch("current")
  WatchCurrent(nVal, oVal) {
    this.$nextTick(() => {
      this.currentIndex = nVal;
      this.scrollByIndex();
    });
  }
  mounted() {
    this.init();
  }
  /**
   * @description: tab选项样式
   * @param {*} index 当前的tab选项
   */
  tabItemStyle(index: number) {
    const style: tabItemStyle = {
      height: this.height + "rpx",
      "font-size": this.fontSize + "rpx",
      "line-height": this.height + "rpx",
      "transition-duration": `${this.duration}s`,
      "margin-right": this.isScroll ? `${this.gutter}rpx` : "0",
      // flex: this.isScroll ? "auto" : "1",
      "padding-bottom": this.barPad + "rpx",
      width:
        this.itemWidth === "auto" ? this.itemWidth : addUnit(this.itemWidth),
    };
    if (this.fontBold) {
      style.fontWeight = "bold";
    }
    if (index === this.currentIndex && this.bold) {
      style.fontWeight = "bold";
    }
    if (index === this.currentIndex) {
      style.color = this.activeColor;
      if (this.activeSize) {
        style["font-size"] = this.activeSize + "rpx";
      }
    } else {
      style.color = this.inactiveColor;
    }
    return style;
  }
  // 设置init方便调用
  async init() {
    // 获取组件信息
    const tabRect: any = await this.getElQuery();
    // tabs组件距离屏幕左边的宽度

    this.parentLeft = tabRect[0].left;

    // tabs组件高度
    this.componentWidth = tabRect[0].width;

    this.getTabRect();
  }
  /**
   * @description: 查询tab的布局信息
   */
  getTabRect() {
    const _this: any = this;
    let queryInfo: any = "";
    queryInfo = uni.createSelectorQuery().in(this);
    for (let i: number = 0; i < this.list.length; i++) {
      queryInfo.select(`#xjw-tabs-tab-item-${i}`).fields({
        size: true,
        rect: true,
      });
    }
    queryInfo.exec(function (res) {
      _this.tabQueryInfo = res;
      _this.scrollByIndex();
    });
  }
  scrollByIndex() {
    if (this.activeSize) {
      this.getTabRect();
    }
    const tabInfo: tabQueryInfoItem = this.tabQueryInfo[this.currentIndex];
    if (!tabInfo) return;
    // 活动tab的宽度
    const tabWidth: number = tabInfo.width;
    this.barWidth = tabWidth * 2;
    // if (this.isScroll) {
    //   this.barWidth = this.barWidth - this.gutter * 2;
    // }
    // 活动item的左边到tabs组件左边的距离，用item的left减去tabs的left
    const offsetLeft = tabInfo.left - this.parentLeft;
    // 将活动的tabs-item移动到屏幕正中间，实际上是对scroll-view的移动
    const scrollLeft = offsetLeft - (this.componentWidth - tabWidth) / 2;
    this.scrollLeft = scrollLeft < 0 ? 0 : scrollLeft;
    // 当前活动item的中点点到左边的距离减去滑块宽度的一半，即可得到滑块所需的移动距离
    const left: number = tabInfo.left + tabInfo.width / 2 - this.parentLeft;
    // 计算当前活跃item到组件左边的距离
    this.scrollBarLeft =
      left - uni.upx2px(this.scrollMargin) - uni.upx2px(this.barWidth) / 2;

    // 第一次移动滑块的时候，barFirstTimeMove为true，放到延时中将其设置false
    // 延时是因为scrollBarLeft作用于computed计算时，需要一个过程需，否则导致出错
    if (this.barFirstTimeMove === true) {
      setTimeout(() => {
        this.barFirstTimeMove = false;
      }, 100);
    }
  }
  clickTab(index: number) {
    if (index === this.currentIndex) return;
    this.currentIndex = index;
    this.scrollByIndex();
    this.$emit("change", index);
  }
  /**
   * @description: 获取节点信息
   */
  getElQuery() {
    return new Promise((resolve) => {
      let queryInfo: any = "";
      queryInfo = uni.createSelectorQuery().in(this);
      queryInfo.select("#" + this.id).boundingClientRect();
      queryInfo.exec((data) => {
        resolve(data);
      });
    });
  }
}
</script>
<style lang="scss" scoped>
view,
scroll-view {
  box-sizing: border-box;
}
::-webkit-scrollbar,
::-webkit-scrollbar,
::-webkit-scrollbar {
  display: none;
  width: 0 !important;
  height: 0 !important;
  -webkit-appearance: none;
  background: transparent;
}
.xjw-tabs-scroll-box {
  position: relative;
}
.xjw-tabs-scroll-box--border-btm {
  border-bottom: 2upx solid #f0f2f5;
}
.xjw-tabs-scroll-view {
  width: 100%;
  white-space: nowrap;
  position: relative;
}

.xjw-tabs-tab-item {
  position: relative;
  display: inline-block;
  text-align: center;
  transition-property: background-color, color;
  .xjw-tabs_dot {
    position: absolute;
    top: 15%;
    right: -12upx;
    width: 12upx;
    height: 12upx;
    background: #ef5656;
    border-radius: 50%;
  }
}

.xjw-tabs-tab-bar {
  position: absolute;
  bottom: 0;
  background-color: $base-color;
}

.xjw-tabs-tabs-scorll-flex {
  display: flex;
  justify-content: space-between;
}
</style>
